#pragma once

#include <nlohmann/json.hpp>
#include "fxcc/core/pch.h"
#include "fxcc/core/Dir.h"

using json = nlohmann::json;

namespace fxcc::json
{

	struct Serializer
	{
		template<typename T>
		void EncodePath(const std::string& p, const T& t)
		{
			nlohmann::json j;
			Encode<T>(j, t);
			fxcc::FileUtil::CreateParentDirs(p);
			std::ofstream ofs(p);
			ofs << j.dump();
			ofs.flush();
			ofs.close();
		}

		template<typename T>
		bool DecodePath(const std::string& p, T& t)
		{
			if (!fs::exists(p))
			{
				return false;
			}
			std::string jsonStr = fxcc::FileUtil::ReadFileToString(p);
			nlohmann::json j = nlohmann::json::parse(jsonStr);

			return Decode<T>(j, t);

		}


		template<typename T>
		void Encode(nlohmann::json& j, const T&);

		template<typename T>
		bool Decode(const nlohmann::json& j, T&);

		template<typename T>
		void SetVariable(nlohmann::json& j, const std::string& field, const T& t)
		{
			nlohmann::json fj;
			Encode<T>(fj, t);
			j[field] = fj;
		}

		template<typename T>
		void SetArrayVariable(nlohmann::json& j, const std::string& field, const std::vector<T>& ts)
		{
			nlohmann::json fj;
			for (const auto& t : ts)
			{
				nlohmann::json f1;
				Encode<T>(f1, t);

				fj.push_back(f1);
			}
			j[field] = fj;
		}

		template<typename T>
		bool GetArrayVariable(const nlohmann::json& j, const std::string& field, std::vector<T>& ts)
		{
			bool flag = j.contains(field);
			if (!flag)
			{
				return false;
			}
			ts.clear();

			nlohmann::json fj;
			for (const auto& f1 : j[field])
			{
				T t;
				Decode<T>(f1, t);

				ts.push_back(t);
			}
			return true;
		}

		template<typename T>
		void SetMapVariable(nlohmann::json& j, const std::string& field, const std::map<std::string, T>& ts)
		{
			nlohmann::json fj;
			for (const auto& [key, t] : ts)
			{
				nlohmann::json f1;
				Encode<T>(f1, t);
				fj[key] = f1;
			}
			j[field] = fj;
		}

		template<typename T>
		bool GetMapVariable(const nlohmann::json& j, const std::string& field, std::map<std::string, T>& ts)
		{
			bool flag = j.contains(field);
			if (!flag)
			{
				return false;
			}
			ts.clear();

			nlohmann::json fj;
			for (const auto& [key, f1] : j[field].items())
			{
				T t;
				Decode<T>(f1, t);
				ts[key] = f1;
			}
			return true;
		}


		template<typename T>
		bool GetVariable(const nlohmann::json& j, const std::string& field, T& t)
		{

			bool flag = j.contains(field);

			if (flag)
			{
				Decode<T>(j[field], t);
			}
			return flag;
		}
	};
};


